﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using AdvanceLib;
using AdvanceLib.ScriptCore;
using ACompiler.SystemCommands;

namespace ACompiler
{
    public class Program
    {
        public static bool error = false;
        public static Script script;
        public static Stopwatch watch = new Stopwatch();

        static void Main(string[] args)
        {
            ScriptHost host = new ScriptHost();
            host.ExtensionManager.SystemCommands.AddRange(Program.GetCommands());

            Console.Title = "ACompiler v0.1.0.0 Pre-Alpha";

            while (true)
            {
                try
                {
                    Program.Write("AdvanceCompiler> ", ConsoleColor.White);

                    string source = Console.ReadLine();
                    error = false;

                    host.Clear(); //Clear errors and offsets

                    host.ExecuteLine(source);

                    Program.PrintErrorList(host.Errors, "Errorlist");
                    Console.WriteLine();

                    if (!error && script != null)
                    {
                        //Program.PrintSuccess();

                        Program.WriteLine("-------------------------------------------------------", ConsoleColor.White);
                        Console.WriteLine();

                        Program.Write("-> Compiling script...      ", ConsoleColor.White);
                        Program.Write("done. ", ConsoleColor.Green);

                        Program.WriteLine("[" + (host.ElapsedTicks / 10000f).ToString() + "ms]", ConsoleColor.Gray);

                        Program.Write("-> Writing script to ROM... ", ConsoleColor.White);

                        watch.Start();
                        host.WriteScriptToROM(script);
                        watch.Stop();

                        Program.Write("done. ", ConsoleColor.Green);
                        Program.WriteLine("[" + (watch.ElapsedTicks / 10000f).ToString() + "ms]", ConsoleColor.Gray);

                        Console.WriteLine();
                        Program.WriteLine("-------------------------------------------------------", ConsoleColor.White);

                        host.ROMStream.Close();
                    }
                    else if (error)
                    {
                        Program.WriteLine("Type 'help' for help.", ConsoleColor.Gray);
                    }

                    watch.Reset();
                    Console.WriteLine();
                }
                catch (Exception ex)
                {
                    Console.WriteLine();

                    //Output exception message
                    Program.WriteLine("Unhandled exception:", ConsoleColor.Yellow);
                    Console.WriteLine(ex.Message);

                    Console.WriteLine(ex.StackTrace);

                    Console.WriteLine();
                }
            }            
        }
        public static void Write(string message, ConsoleColor color)
        {
            ConsoleColor backup = Console.ForegroundColor;

            Console.ForegroundColor = color;
            Console.Write(message);
            Console.ForegroundColor = backup;
        }
        public static void WriteLine(string message, ConsoleColor color)
        {
            Write(message + System.Environment.NewLine, color);
        }
        public static IEnumerable<ISystemCommand> GetCommands()
        {
            yield return new SystemCommands.Compile();
            yield return new SystemCommands.CompileAndOutput();
            yield return new SystemCommands.Help();
            yield return new SystemCommands.ReloadPlugins();
        }
        public static void PrintErrorList(List<DebugError> errorList, string title)
        {
            if (errorList.Count > 0)
            {
                Console.WriteLine();
                Program.WriteLine(title + ":", ConsoleColor.White);

                foreach (DebugError error in errorList)
                {
                    Program.Write(error.Line.ToString() + ": ", ConsoleColor.Yellow);
                    Program.WriteLine(error.Message, ConsoleColor.Gray);
                }

                Program.error = true;
            }
        }
        public static void PrintSuccess()
        {
            int sectionIndex = 0;
            int commandIndex = 0;
            int dataIndex = 0;

            foreach (ScriptSection section in script.Sections)
            {
                byte[] data = new byte[section.Size];
                dataIndex = 0;

                for (int i = 0; i < data.Length; i++)
                {
                    data[i] = script.Data[section.Offset][i];
                }
                sectionIndex += section.Size;

                Program.Write("Offset " + section.Name, ConsoleColor.Yellow);
                Program.WriteLine(" [0x" + section.Offset.ToString("X2") + "]", ConsoleColor.White);

                commandIndex = 0;
                foreach (ICommand command in section.Commands)
                {
                    Program.Write("cmd_" + (commandIndex++).ToString(), ConsoleColor.White);
                    for (int i = 0; i < command.GetLength(); i++)
                    {
                        Program.Write(" 0x" + data[dataIndex++].ToString("X2"), ConsoleColor.Gray);
                    }
                    Console.WriteLine();
                }
                Console.WriteLine();
            }
        }
    }
}
